package com.scs.application.modules.sys.security;

import com.scs.application.core.exception.BusinessException;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.service.DeptService;
import com.scs.application.modules.fsd.entity.FsdRole;
import com.scs.application.modules.fsd.entity.FsdUser;
import com.scs.application.modules.fsd.service.FsdRoleService;
import com.scs.application.modules.fsd.service.FsdUserService;
import com.scs.application.modules.sys.entity.OnlineUser;
import com.scs.application.modules.sys.entity.Role;
import com.scs.application.modules.sys.entity.User;
import com.scs.application.modules.sys.properties.SystemProperties;
import com.scs.application.modules.sys.service.OnlineUserService;
import com.scs.application.modules.sys.service.RoleService;
import com.scs.application.modules.sys.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.List;
import java.util.stream.Collectors;

/**
 * token 鉴权、授权
 */
public class AccessTokenRealm extends AuthorizingRealm {

    public static final String CACHE_NAME = "shiroCache";

    @Autowired
    @Lazy
    private UserService userService;
    @Autowired
    @Lazy
    private FsdUserService fsdUserService;

    @Autowired
    @Lazy
    private OnlineUserService onlineUserService;


    @Autowired
    @Lazy
    private RoleService roleService;
    @Autowired
    @Lazy
    private FsdRoleService fsdRoleService;

    @Autowired
    @Lazy
    private DeptService deptService;

    @Autowired
    private SystemProperties systemProperties;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof AccessToken;
    }

    /**
     * 授权函数
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        final SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        User currentUser = (User) SecurityUtils.getSubject().getPrincipal();

//        List<Role> roles = userService.getUserRoles(currentUser);
//
//        // 添加角色
//        simpleAuthorizationInfo.addRoles(roles.stream().map(role -> role.getRoleCode()).collect(Collectors.toList()));

        // 测试时使用
        simpleAuthorizationInfo.addStringPermission("*");

        // 如果是超级用户，直接加所有的权限
//        if (currentUser.isSuperAdmin()) {
//            simpleAuthorizationInfo.addStringPermission("*");
//        } else {
//            List<Right> userRights = userService.getUserRights(currentUser);
//            userRights.stream().filter(o -> StringUtils.isNotBlank(o.getPermissions())).forEach(o -> {
//                simpleAuthorizationInfo.addStringPermissions(Lists.newArrayList(StringUtils.split(o.getPermissions(), ";")));
//            });
//        }


        return simpleAuthorizationInfo;
    }

    /**
     * 认证函数,登录时调用
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String accessToken = (String) authenticationToken.getPrincipal();

//        //根据accessToken，查询用户信息
        OnlineUser token = onlineUserService.findByToken(accessToken);
        //token失效
        if (token == null || token.getGmtExpire().getTime() < System.currentTimeMillis()) {
            throw new ExpiredCredentialsException("token失效，请重新登录");
        }
        //柜子登录
        if(token.getDeviceType().equals("1")){
            FsdUser fsdUser = fsdUserService.findByCode(token.getUserCode());
            if (fsdUser == null) {
                throw new UnknownAccountException("未知的帐号信息");
            }
            //将柜子用户转存到系统用户实体中，达到共用登录验证的目的。柜子只取登录用户的id和工号
            User user = new User();
            user.setId(fsdUser.id);
            user.setWorkNo(fsdUser.getJobNumber());
            UserPrincipal principal = new UserPrincipal();
            BeanUtils.copyProperties(user, principal);
            List<FsdRole> roles = fsdRoleService.listRoleByUserId(user.getId());
            principal.setRoleCodes(roles.stream().map(o -> o.getRoleKey()).collect(Collectors.toList()));
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, accessToken, getName());
            return info;
        }
        //查询用户信息
        User user = userService.findByCode(token.getUserCode());
        if (user == null) {
            throw new UnknownAccountException("未知的帐号信息");
        }

        //账号锁定
//        if (User.STATUS_LOCKED.equals(user.getStatus())) {
//            throw new LockedAccountException("您的账号已被锁定");
//        }

        /**
         * 此处 principal 的值为 {@link User}类型，所以在 {@link AuthorizingRealm#getAuthorizationInfo} 从缓存里面加载信息时，
         * key 为 {@link User} 对象，需重写 {@link User#equals(Object)} 和 {@link User#hashCode()} 方法
         */
        UserPrincipal principal = new UserPrincipal();
        BeanUtils.copyProperties(user, principal);


        List<Role> roles = roleService.listUserRole(user.getId());
        principal.setRoleCodes(roles.stream().map(o -> o.getCode()).collect(Collectors.toList()));

//        principal.setLineId((String) CacheUtils.get("user_token:" + accessToken + ":lineId"));

//        Office office = (Office) CacheUtils.get(CacheUtils.SYS_CACHE, CacheConsts.SYS_OFFICE_ID_PREFIX + user.getOfficeId());
//        if(office != null){
//            principal.setOfficeName(office.getName());
//        }
        //查询部门信息
        Dept dept = deptService.getById(user.getOfficeId());
        if(dept == null) throw new BusinessException("登录用户没找到有效科室");

        principal.setDeptId(dept.getId());
        principal.setOfficeId(dept.getId());
        principal.setDeptName(dept.getName());
        principal.setDeptBusType(dept.getBusType().toString());
        principal.setDeptFlagBus(dept.getFlagBus().toString());
        principal.setDeptDataAll(dept.getFlagAllData());
        principal.setFlagProject(systemProperties.getFlagProject());
        principal.setDeptIds(deptService.listByUserId(user.getId(), user.getOfficeId()).stream().map(Dept::getId).limit(10).collect(Collectors.toList())); //最多取10个，多了会报错


        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, accessToken, getName());
        return info;
    }


    @Override
    public String getName() {
        return super.getName();
    }
}
